package jmind.core.aspect;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;
import jmind.base.annotation.CacheMonitor;
import jmind.base.cache.ICache;
import jmind.core.cache.support.Cache;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.util.*;

/**
 * description:
 *
 * @author weibo.xie
 * @date : create in 5:04 下午 2021/5/18
 */
public class CacheJsonAspect extends AbstractCacheAspect {

    public final Map<Method, Class> M = Maps.newConcurrentMap();

    @Override
    public ICache getCache(CacheMonitor monitor) {
        return Cache.getCache().getCache(monitor.type(), monitor.name());
    }

    public Object getByCache(MethodSignature signature, CacheMonitor monitor, ICache cache, String key) throws Throwable {
        Object obj = cache.get(key);
        if(monitor.type()!= ICache.Type.REDIS || obj==null){
            return obj;
        }
         return parseJsonValue(signature,obj.toString());
    }

    public Map<String, Object> getByCache(MethodSignature signature, CacheMonitor monitor, ICache cache, Collection<String> keys){
        if(monitor.type()== ICache.Type.REDIS ){
            Class aClass = getRawType(signature, signature.getReturnType(), 1);
            return cache.getObjects(keys,aClass);
        }

        return cache.getMulti(keys);

    }


    private final Object parseJsonValue(final MethodSignature signature, String obj) throws Throwable {
        Class returnType = signature.getReturnType();
        if (returnType.equals(String.class)) { // String 直接返回
            return obj;
        } else if (List.class.isAssignableFrom(returnType)) { // List 特许处理
            List<?> list = JSON.parseArray(obj, getRawType(signature, returnType, 0));
            //  不是接口，并且不是arraylist实例
            if (!returnType.isInterface() && !returnType.isInstance(list)) {
                List o = (List) returnType.newInstance();
                o.addAll(list);
                return o;
            }
            return list;
        } else if (Set.class.isAssignableFrom(returnType)) {
            List list = JSON.parseArray(obj, getRawType(signature, returnType, 0));
            if (returnType.isInterface()) {
                return new HashSet<>(list);
            }
            Set set = (Set) returnType.newInstance();
            set.addAll(list);
            return set;
        } else if (Map.class.isAssignableFrom(returnType)) {
            // if(aClass.equals(String.class) || Number.class.isAssignableFrom(aClass))
            Map map = JSON.parseObject(obj, Map.class);
            Class aClass = getRawType(signature, returnType, 1);
            //  这里判断不是基础类型，需要单个继续转换
            if (!map.isEmpty() && map.values().iterator().next().getClass() != aClass) {
                Map mm = new HashMap();
                map.forEach((k, v) -> mm.put(k, JSON.parseObject(v.toString(), aClass)));
                return mm;
            }
            return map;
        }
        // Primitive,Number,Map,List,set 都能支持
        return JSON.parseObject(obj, signature.getReturnType());

    }


    private final Class getRawType(MethodSignature signature, Class returnType, int index) {
        return M.computeIfAbsent(signature.getMethod(), m -> {
            java.lang.reflect.Type type = m.getGenericReturnType();
            TypeToken<?> type2 = TypeToken.of(type).resolveType(returnType.getTypeParameters()[index]);
            return type2.getRawType();
        });

    }

}